home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Magazin: Amiga-CD 1996 May & June
/
Amiga-CD 1996 #5-6.iso
/
kommunikation
/
ipdial
/
serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-22
|
15KB
|
682 lines
/**
*** IPDial Script program for initializing a SLIP connection
*** Copyright (C) 1994 Jochen Wiedmann
***
*** This program is free software; you can redistribute it and/or modify
*** it under the terms of the GNU General Public License as published by
*** the Free Software Foundation; either version 2 of the License, or
*** (at your option) any later version.
***
*** This program is distributed in the hope that it will be useful,
*** but WITHOUT ANY WARRANTY; without even the implied warranty of
*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*** GNU General Public License for more details.
***
*** You should have received a copy of the GNU General Public License
*** along with this program; if not, write to the Free Software
*** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***
***
***
*** This file implements the communication with the serial.device.
***
***
*** Computer: Amiga 1200 Compiler: Dice 3.01
***
*** Author: Jochen Wiedmann
*** Am Eisteich 9
*** 72555 Metzingen
*** Germany
***
*** Phone: (+0049) 7123 / 14881
*** Internet: wiedmann@neckar-alb.de
**/
/**
*** Include files
**/
#ifndef IPDIAL_H
#include "IPDial.h"
#endif
#include <ctype.h>
#include <devices/serial.h>
#include <devices/timer.h>
#ifndef MIN
#define MIN(a,b) (((a)>(b))?(b):(a))
#endif
/**
*** Local variables.
**/
STATIC APTR MySerReq = NULL;
STATIC APTR MyTimeReq = NULL;
STATIC UBYTE SerBuffer[4096];
/**
*** Cleanup function.
**/
VOID SerialCleanup(VOID)
{ DeviceIODelete(MySerReq);
DeviceIODelete(MyTimeReq);
}
/**
*** Table of error messages created by the serial.device.
**/
STATIC VOID SerialShowError(ULONG Error)
{ STRPTR ptr;
switch(Error)
{ case 1:
ptr = (STRPTR) "Serial device busy";
break;
case 2:
ptr = (STRPTR) "Baud rate not supported";
break;
case 4:
ptr = (STRPTR) "Memory error";
break;
case 5:
ptr = (STRPTR) "Invalid parameters";
break;
case 6:
ptr = (STRPTR) "Line error";
break;
case 9:
ptr = (STRPTR) "Parity error";
break;
case 11:
ptr = (STRPTR) "Timer error";
break;
case 12:
ptr = (STRPTR) "Buffer overflow";
break;
case 13:
ptr = (STRPTR) "No DSR";
break;
case 15:
ptr = (STRPTR) "Break detected";
break;
default:
ptr = (STRPTR) "Unknown error";
break;
}
fprintf(stderr, "Serial device: %s.\n", ptr);
}
/**
*** This function opens the serial device. It can be closed
*** using DeviceIODelete().
**/
STATIC ULONG SerialDecodeProtocol(struct IOExtSer *SerReq, STRPTR Protocol)
{ if (stricmp((char *) Protocol, "XONXOFF") == 0)
{ SerReq->io_SerFlags &= ~(SERF_XDISABLED|SERF_7WIRE);
}
else if (stricmp((char *) Protocol, "NONE") == 0)
{ SerReq->io_SerFlags |= SERF_XDISABLED;
SerReq->io_SerFlags &= ~SERF_7WIRE;
}
else if (stricmp((char *) Protocol, "RTSCTS") == 0 ||
stricmp((char *) Protocol, "7WIRE") == 0)
{ SerReq->io_SerFlags |= (SERF_XDISABLED|SERF_7WIRE);
}
else
{ return(FALSE);
}
return(TRUE);
}
ULONG SerialOpen(STRPTR DeviceName, STRPTR Protocol, ULONG Unit)
{ ULONG error;
struct IOExtSer *RealSerReq;
if (!(MySerReq = DeviceIOCreate(sizeof(struct IOExtSer))))
{ fprintf(stderr, "Failed to open %s: Memory error.\n",
DeviceName);
exit(10);
}
RealSerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
RealSerReq->io_SerFlags = 0;
if (Protocol)
{ if (!SerialDecodeProtocol(RealSerReq, Protocol))
{ return(FALSE);
}
}
if ((error = DeviceIOOpen(DeviceName, Unit, MySerReq, 0)))
{ SerialShowError(error);
exit(10);
}
if(Protocol)
{ SerialSetProtocol(Protocol);
}
if (!(MyTimeReq = DeviceIOCreate(sizeof(struct timerequest))))
{ fprintf(stderr, "Failed to open timer.device: Memory error.\n");
exit(10);
}
if ((error = DeviceIOOpen((STRPTR) "timer.device", UNIT_VBLANK,
MyTimeReq, 0)))
{ fprintf(stderr, "Failed to open timer.device: Error %ld\n", error);
exit(10);
}
return(TRUE);
}
/**
*** This function sends a string to the serial device.
**/
VOID SerialSend(STRPTR str, ULONG len)
{ struct IOExtSer *req;
#ifdef DEBUG
printf("SerialSend: %s\n", str);
#endif
req = (struct IOExtSer *) DeviceIOReq(MySerReq);
req->IOSer.io_Length = strlen((char*) str);
req->IOSer.io_Data = str;
DeviceIODo(MySerReq, CMD_WRITE);
}
/**
*** This function is used to wait for a certain string.
***
*** The function will return if either a timeout occurs
*** (never happens, if timeout == -1) or if one of the
*** strings in the args array is read from the serial.device.
***
*** Result is the number of the string or -1.
**/
STATIC APTR waitBuffer = NULL;
LONG SerialWait(STRPTR *args, LONG timeout)
{ ULONG sigs;
ULONG rsigs;
BYTE error;
struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
/**
*** Be sure, that the buffer is valid.
**/
if (!waitBuffer && !(waitBuffer = BufferCreate()))
{ perror("malloc");
exit(10);
}
/**
*** Clear the buffer.
**/
BufferClear(waitBuffer);
sigs = SIGBREAKF_CTRL_C | DeviceIOSignal(MySerReq);
if (timeout != -1)
{ struct timerequest *tr = (struct timerequest *) DeviceIOReq(MyTimeReq);
tr->tr_time.tv_secs = timeout;
tr->tr_time.tv_micro = 0;
DeviceIOSend(MyTimeReq, TR_ADDREQUEST);
sigs |= DeviceIOSignal(MyTimeReq);
}
for(;;)
{ LONG result;
/**
*** First ask, if any data is present on the serial line.
*** May be, the string we are waiting for is already present?
**/
do
{ DeviceIODo(MySerReq, SDCMD_QUERY);
if ((result = SerReq->IOSer.io_Actual))
{ SerReq->IOSer.io_Data = SerBuffer;
SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1, SerReq->IOSer.io_Actual);
if ((error = DeviceIODo(MySerReq, CMD_READ)))
{ SerialShowError(error);
exit(10);
}
if (EchoMode)
{ int i;
for (i = 0; i < SerReq->IOSer.io_Actual; i++)
{ putchar(SerBuffer[i]);
}
fflush(stdout);
}
BufferExtend(waitBuffer, SerBuffer, SerReq->IOSer.io_Actual);
}
}
while (result);
if ((result = BufferCheck(waitBuffer, args)) >= 0)
{ DeviceIOAbort(MyTimeReq);
return(result);
}
/**
*** It isn't, send a request for one byte.
**/
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
rsigs = Wait(sigs);
if (rsigs & SIGBREAKF_CTRL_C)
{ printf("Ctrl-C\n");
exit(10);
}
else if (rsigs & DeviceIOSignal(MySerReq))
{ BYTE error;
/**
*** Data received, add it to the buffer and check for more.
**/
if ((error = DeviceIOWait(MySerReq)))
{ SerialShowError(error);
exit(10);
}
if (EchoMode)
{ putchar(*SerBuffer);
fflush(stdout);
}
BufferExtend(waitBuffer, SerBuffer, 1);
}
else
{ /**
*** Timeout
**/
DeviceIOWait(MyTimeReq);
DeviceIOAbort(MySerReq);
return(-1);
}
}
}
/**
*** Return buffer read by the last "Wait" command.
**/
STRPTR SerialWaitBuffer(VOID)
{ if (!(waitBuffer))
{ return((STRPTR) "");
}
else
{ return(BufferBuffer(waitBuffer));
}
}
/**
*** This function implements a terminal mode. It gives the users input
*** to the modem and likewise the modems output to the user, as long as
*** the user doesn't enter Ctrl-\.
**/
VOID SerialTerminal(STRPTR eof, ULONG echo, ULONG lineMode)
{ struct DosPacket *dp;
struct MsgPort *port = NULL;
struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
APTR SerSendReq = NULL;
struct IOExtSer *serSendReq;
char buffer[128];
char sendBuffer[256]; /* Twice the size of buffer */
ULONG bufSize = sizeof(buffer);
ULONG status = 10;
BPTR cis = Input();
ULONG sigs;
if (!cis)
{ fprintf(stderr, "Can't use nil: as input device.\n");
exit(10);
}
if (!echo) {
lineMode = FALSE;
}
if (!lineMode) {
if (!SetMode(cis, TRUE)) {
fprintf(stderr, "Can't put console into character (raw) mode.\n");
exit(10);
}
bufSize = 128;
}
if ((dp = AllocDosObject(DOS_STDPKT, NULL)))
{ if ((port = CreateMsgPort()))
{ if ((SerSendReq = DeviceIOCreate(sizeof(struct IOExtSer))))
{ serSendReq = (struct IOExtSer *) DeviceIOReq(SerSendReq);
serSendReq->IOSer.io_Device = SerReq->IOSer.io_Device;
serSendReq->IOSer.io_Unit = SerReq->IOSer.io_Unit;
status = 0;
}
}
}
if (status)
{ fprintf(stderr, "Memory error.\n");
goto ExitSerialTerminal;
}
dp->dp_Type = ACTION_READ;
dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
dp->dp_Arg2 = (ULONG) buffer;
dp->dp_Arg3 = bufSize;
SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type, port);
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
sigs = (1 << port->mp_SigBit) | SIGBREAKF_CTRL_C | DeviceIOSignal(MySerReq);
for(;;)
{ LONG rsigs;
rsigs = Wait(sigs);
if (rsigs & SIGBREAKF_CTRL_C)
{ fprintf(stderr, "Ctrl-C\n");
status = 5;
DeviceIOAbort(MySerReq);
AbortPkt(port, dp);
WaitPort(port);
goto ExitSerialTerminal;
}
if (rsigs & (1 << port->mp_SigBit))
{ int eofSeen = FALSE;
GetMsg(port);
if (dp->dp_Res1 == -1)
{ fprintf(stderr, "Error %ld while reading input.\n", dp->dp_Res2);
status = 10;
}
if (dp->dp_Res1 == 0)
{ eofSeen = TRUE;
}
else
{ int i, bufLen; /* Extend LF to CR/LF and send resulting string. */
bufLen = 0;
for (i = 0; i < dp->dp_Res1; i++)
{ if ((eof && *eof == buffer[i]) ||
(!eof && !lineMode && buffer[i] == '\0x1c'))
{ eofSeen = TRUE;
}
if (lineMode && buffer[i] == '\n')
{ sendBuffer[bufLen++] = '\r';
sendBuffer[bufLen++] = '\n';
}
else
{ sendBuffer[bufLen++] = buffer[i];
}
}
if (bufLen > 0)
{ serSendReq->IOSer.io_Length = bufLen;
serSendReq->IOSer.io_Data = sendBuffer;
DeviceIODo(SerSendReq, CMD_WRITE);
}
if (!lineMode && echo)
{ fwrite(sendBuffer, bufLen, 1, stdout);
fflush(stdout);
}
}
if (eofSeen)
{ DeviceIOAbort(MySerReq);
goto ExitSerialTerminal;
}
dp->dp_Type = ACTION_READ;
dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
dp->dp_Arg2 = (ULONG) buffer;
dp->dp_Arg3 = bufSize;
SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type, port);
}
if (rsigs & DeviceIOSignal(MySerReq))
{ LONG error;
LONG result;
if ((error = DeviceIOWait(MySerReq)))
{ SerialShowError(error);
AbortPkt(port, dp);
WaitPort(port);
goto ExitSerialTerminal;
}
putchar(*SerBuffer);
fflush(stdout);
do
{ DeviceIODo(MySerReq, SDCMD_QUERY);
if ((result = SerReq->IOSer.io_Actual))
{ SerReq->IOSer.io_Data = SerBuffer;
SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1, SerReq->IOSer.io_Actual);
if ((error = DeviceIODo(MySerReq, CMD_READ)))
{ SerialShowError(error);
exit(10);
}
fwrite(SerBuffer, SerReq->IOSer.io_Actual, 1, stdout);
fflush(stdout);
}
}
while (result);
SerReq->IOSer.io_Length = 1;
SerReq->IOSer.io_Data = SerBuffer;
DeviceIOSend(MySerReq, CMD_READ);
}
}
ExitSerialTerminal:
if (dp)
{ FreeDosObject(DOS_STDPKT, dp);
}
if (port)
{ DeleteMsgPort(port);
}
if (SerSendReq)
{ DeviceIODelete(SerSendReq);
}
if (!lineMode)
{ SetMode(cis, FALSE);
}
if (status)
{ exit(status);
}
}
/**
*** This function shows the current serial parameters.
**/
VOID SerialShowParms(VOID)
{ STRPTR Parity, Protocol;
struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
printf("\tBaud = %ld\n", SerReq->io_Baud);
printf("\tDataBits = %ld\n", (ULONG) SerReq->io_ReadLen);
printf("\tStopBits = %ld\n", (ULONG) SerReq->io_StopBits);
printf("\tBufSize = %ld\n", SerReq->io_RBufLen);
if (SerReq->io_SerFlags & SERF_PARTY_ON)
{ if (SerReq->io_SerFlags & SERF_PARTY_ODD)
{ Parity = (STRPTR) "Odd";
}
else
{ Parity = (STRPTR) "Even";
}
}
else
{ Parity = (STRPTR) "None";
}
printf("\tParity = %s\n", Parity);
if (SerReq->io_SerFlags & SERF_7WIRE)
{ if (SerReq->io_SerFlags & SERF_XDISABLED)
{ Protocol = (STRPTR) "RTS/CTS";
}
else
{ Protocol = (STRPTR) "RTS/CTS, XON/XOFF";
}
}
else
{ if (SerReq->io_SerFlags & SERF_XDISABLED)
{ Protocol = (STRPTR) "None";
}
else
{ Protocol = (STRPTR) "XON/XOFF";
}
}
printf("\tProtocol = %s\n\n", Protocol);
}
/**
*** Some functions for setting serial parameters.
**/
VOID SerialSetBaud(ULONG Baud)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
SerReq->io_Baud = Baud;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
VOID SerialSetDataBits(UBYTE DataBits)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
SerReq->io_ReadLen = SerReq->io_WriteLen = DataBits;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
VOID SerialSetStopBits(UBYTE StopBits)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
SerReq->io_StopBits = StopBits;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
VOID SerialSetBufSize(ULONG BufSize)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
if (BufSize & 0x3f)
{ fprintf(stderr,
"Warning: BufSize must be a multiple of 64, rounding up.\n");
BufSize = (BufSize & 0x3f) + 0x40;
}
SerReq->io_RBufLen = BufSize;
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
}
ULONG SerialSetParity(STRPTR Parity)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
if (stricmp((char *) Parity, "NONE") == 0)
{ SerReq->io_SerFlags &= ~SERF_PARTY_ON;
}
else if (stricmp((char *) Parity, "EVEN") == 0)
{ SerReq->io_SerFlags |= SERF_PARTY_ON;
SerReq->io_SerFlags &= ~SERF_PARTY_ODD;
}
else if (stricmp((char *) Parity, "ODD") == 0)
{ SerReq->io_SerFlags |= (SERF_PARTY_ON|SERF_PARTY_ODD);
}
else
{ return(FALSE);
}
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
return(TRUE);
}
ULONG SerialSetProtocol(STRPTR Protocol)
{ struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
BYTE error;
if (!(SerialDecodeProtocol(SerReq, Protocol)))
{ return(FALSE);
}
if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
{ SerialShowError(error);
exit(10);
}
return(TRUE);
}